using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using Microsoft.ApplicationBlocks.Data;
using System.Xml;
using System.Collections;
using System.Data;

namespace Microsoft.SharedSource.SqlServer.MDDE.Repository
{
    public sealed class InstanceScalarProperty
    {
        #region Fields

        InstanceConfigurableComponent parentComponent;
        string name;
        string value;
        string type;

        #endregion

        #region Properties

        public string Name
        {
            get { return name; }
        }

        public string Value
        {
            get { return this.value; }
            set { this.value = value; }
        }

        public string Type
        {
            get { return type; }
            set { type = value; }
        }

        public InstanceConfigurableComponent ParentComponent
        {
            get { return parentComponent; }
        }

        #endregion

        #region Methods

        public InstanceScalarProperty
            (InstanceConfigurableComponent parentComponent,
            string propertyName)
            : this(parentComponent, propertyName, null) { }

        public InstanceScalarProperty
            (InstanceConfigurableComponent parentComponent,
            string propertyName, SqlTransaction tn)
        {
            this.parentComponent = parentComponent;
            this.name = propertyName;

            // Get scalar property info from the repository.
            SqlParameter[] sqlParams = new SqlParameter[2];
            sqlParams[0] = new SqlParameter("@componentId",
                parentComponent.Id);
            sqlParams[1] = new SqlParameter("@propertyName",
                this.Name);

            DataSet propInfo;
            if (tn == null)
                propInfo =
                    SqlHelper.ExecuteDataset(
                    parentComponent.ParentInstance.
                    ParentTemplate.ParentRepository.RepositoryConnection,
                    CommandType.Text,
                    Resource.GetInstancePropInfo, sqlParams);
            else
                propInfo =
                    SqlHelper.ExecuteDataset(
                    tn,
                    CommandType.Text,
                    Resource.GetInstancePropInfo, sqlParams);

            // Return if no instance is found.
            if (propInfo.Tables[0].Rows.Count == 0)
                return;

            this.value =
                propInfo.Tables[0].Rows[0]["PropertyValue"].ToString();
        }

        internal void Create(SqlTransaction inputTxn)
        {
            // Create a new transaction if there is no input transaction.
            SqlTransaction txn = inputTxn != null ? inputTxn :
                parentComponent.
                ParentInstance.ParentTemplate.ParentRepository.
                RepositoryConnection.BeginTransaction();

            try
            {
                SqlParameter[] sqlParams = new SqlParameter[4];
                sqlParams[0] =
                    new SqlParameter("@componentId",
                    parentComponent.Id);
                sqlParams[1] =
                    new SqlParameter("@propertyName",
                    this.Name);
                sqlParams[2] =
                    new SqlParameter("@propertyType", this.Type);
                sqlParams[3] =
                    new SqlParameter("@propertyValue", this.Value);

                SqlHelper.ExecuteNonQuery(txn,
                    CommandType.StoredProcedure,
                    "sp_CreateInstanceScalarProperty",
                    sqlParams);

                // Commit the transaction if it is not an input one.
                if (inputTxn == null)
                    txn.Commit();
            }
            catch (Exception ex)
            {
                // Rollback the transaction if it is not an input one.
                if (inputTxn == null)
                    txn.Rollback();
                throw ex;
            }
        }

        internal void Update(SqlTransaction inputTxn)
        {
            // Create a new transaction if there is no input transaction.
            SqlTransaction txn = inputTxn != null ? inputTxn :
                parentComponent.
                ParentInstance.ParentTemplate.ParentRepository.
                RepositoryConnection.BeginTransaction();

            try
            {
                SqlParameter[] sqlParams = new SqlParameter[3];
                sqlParams[0] =
                    new SqlParameter("@componentId",
                    parentComponent.Id);
                sqlParams[1] =
                    new SqlParameter("@propertyName",
                    this.Name);
                sqlParams[2] =
                    new SqlParameter("@propertyValue",
                    this.Value);

                SqlHelper.ExecuteNonQuery(txn,
                    CommandType.StoredProcedure,
                    "sp_UpdateInstanceScalarProperty",
                    sqlParams);

                // Commit the transaction if it is not an input one.
                if (inputTxn == null)
                    txn.Commit();
            }
            catch (Exception ex)
            {
                // Rollback the transaction if it is not an input one.
                if (inputTxn == null)
                    txn.Rollback();
                throw ex;
            }
        }

        #endregion

        internal void ApplyProperties(XmlNode xProperty)
        {
            this.value = xProperty.Attributes["Value"].Value;
        }

        internal void Delete(SqlTransaction txn)
        {
            // Delete mapping.
            SqlParameter[] sqlParams = new SqlParameter[2];
            sqlParams[0] = new SqlParameter(
                "@componentId", parentComponent.Id);
            sqlParams[1] = new SqlParameter(
                "@propertyName", this.Name);

            SqlHelper.ExecuteNonQuery(txn,
                CommandType.StoredProcedure,
                "sp_DeleteInstanceScalarProperty",
                sqlParams);
        }
    }

    public sealed class InstanceScalarPropertyCollection : IEnumerable
    {
        #region Fields

        private Dictionary<string, InstanceScalarProperty>
            instanceProperties =
            new Dictionary<string, InstanceScalarProperty>();

        InstanceConfigurableComponent parentComponent;

        #endregion

        #region Properties

        public int Count
        {
            get { return instanceProperties.Count; }
        }

        public InstanceConfigurableComponent ParentComponent
        {
            get { return parentComponent; }
        }

        public InstanceScalarProperty this[string propertyName]
        {
            get { return instanceProperties[propertyName]; }
        }

        #endregion

        #region Methods

        internal InstanceScalarPropertyCollection(
            InstanceConfigurableComponent parentComponent)
        {
            this.parentComponent = parentComponent;
        }

        public void Add(InstanceScalarProperty instanceProp)
        {
            instanceProperties.Add(instanceProp.Name, instanceProp);
        }

        public void Remove(InstanceScalarProperty instanceProp)
        {
            instanceProperties.Remove(instanceProp.Name);
        }

        public bool ContainsProperty(string propertyName)
        {
            return instanceProperties.ContainsKey(propertyName);
        }

        internal void Clear()
        {
            instanceProperties.Clear();
        }

        #endregion

        #region IEnumerable Members

        public IEnumerator GetEnumerator()
        {
            return instanceProperties.Values.GetEnumerator();
        }

        #endregion
    }
}
